package progetto1.csm.main;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import progetto1.csm.core.DataExporter;
import progetto1.csm.core.Scenario;
import progetto1.csm.core.StatisticType;
import progetto1.csm.core.Statistics;
import progetto1.csm.core.SystemElement;
import progetto1.csm.implementation.CSMScenario;
import progetto1.csm.implementation.CSMStatisticsE;
import progetto1.csm.implementation.CSMStatisticsTypes;
import progetto1.csm.implementation.CSMStatisticsTypesE;
import progetto1.csm.implementation.CSMSystemElements;
import progetto1.csm.implementation.CSVFileBuilder;
import progetto1.csm.implementation.DataExporterImp;
import progetto1.csm.implementation.SystemFactory;
import sde.actor.distribution.Distribution;
import sde.actor.distribution.ErlangDistribution;
import sde.actor.distribution.ExponentialDistribution;
import sde.actor.distribution.HyperexponentialDistribution;

public class Main2 {
	public static void main(String[] args) {
		//Per il calcolo dell'intervallo di confidenza  sono stati eseguiti unt totale di n esperimenti
		int n = 32;
		double sqrtN = Math.sqrt(n);
		double confidenceDegree = 1.960;//95%
		// variabili per le distribuzioni e per l'ambiente
		double lambdaS0 = 0.01, lambdaS1_1 = 1, lambdaS1_2 = 2.3, lambdaS2 = 0.8, lambdaS3 = 0.6;
		int nS3 = 16;
		double alfaS4[] = { 0.95, 0.05 };
		double lambdaS4[] = { 5, 0.5 };
		double tend = 3 * Math.pow(10, 7);
		int k[] = { 2, 5, 10, 20 };
		// file dei due scenari
		String fileScenario1 = "C:\\Users\\Valerio\\Desktop\\scenario1.csv";
		String fileScenario2 = "C:\\Users\\Valerio\\Desktop\\scenario2.csv";
		
		// settaggio dell'ambiente
		SystemFactory.setTimeSimulation(tend);
		//tipi di elementi e statistiche
		SystemElement[] se = CSMSystemElements.values();
		StatisticType[] st1 = CSMStatisticsTypes.values();
		StatisticType[] st2 = CSMStatisticsTypesE.values();
		//creazione esportatori e scenari
		DataExporter de[] = {
				new DataExporterImp(new CSVFileBuilder(fileScenario1)),
				new DataExporterImp(new CSVFileBuilder(fileScenario2)) };
		progetto1.csm.core.System sys;// variabile del sistema
		// simulazioni
		for (int i = 0; i < 2; i++) {
			for (int j = 0; j < k.length; j++) {
				CSMStatisticsE result = new CSMStatisticsE();
				result.setNClient(k[j]);
				double sums[][] = new double[CSMSystemElements.values().length][3];
				List<Statistics> stats = new LinkedList<>();// lista di tutte le statistiche raccolte
				System.out.println("Inizio simulazione dello scenario "+(i+1)+" con k="+k[j]);
				for (int x = 0; x < n; x++) {
					Random random = new Random();
					// distribuzioni
					Distribution d0 = new ExponentialDistribution(lambdaS0, random);
					Distribution d1[] = new Distribution[]{new ExponentialDistribution(lambdaS1_1, random),new ExponentialDistribution(lambdaS1_2, random)};
					Distribution d2 = new ExponentialDistribution(lambdaS2, random);
					Distribution d3 = new ErlangDistribution(nS3, lambdaS3, random);
					Distribution d4 = new HyperexponentialDistribution(alfaS4, lambdaS4,
							random);
					Scenario s =  new CSMScenario(d0, d1[i], d2, d3, d4);
					sys = SystemFactory.create(s);
					stats.add(sys.simulate(k[j]));
					System.out.println("x="+(x+1));
				}
				System.out.println("Calcolo nuove statistiche");
				for(Statistics stat:stats){
					for(SystemElement element:se){
						sums[element.getOrdinal()][0] += stat.getValue(st1[0], element);//Utilization
						sums[element.getOrdinal()][1] += stat.getValue(st1[1], element);//Throughput
						sums[element.getOrdinal()][2] += stat.getValue(st1[2], element);//ResponseTime
					}
				}
				for (int y = 0; y < sums.length; y++) {//avarage
					result.addStatistic(st2[0], se[y], sums[y][0]/n);
					result.addStatistic(st2[5], se[y], sums[y][1]/n);
					result.addStatistic(st2[10], se[y], sums[y][2]/n);
					sums[y][0]=0;sums[y][1]=0;sums[y][2]=0;
				}
				for(Statistics stat:stats){
					for(SystemElement element:se){
						sums[element.getOrdinal()][0] += Math.pow(stat.getValue(st1[0], element)-result.getValue(st2[0], element),2);//Utilization
						sums[element.getOrdinal()][1] += Math.pow(stat.getValue(st1[1], element)-result.getValue(st2[5], element),2);//Throughput
						sums[element.getOrdinal()][2] += Math.pow(stat.getValue(st1[2], element)-result.getValue(st2[10], element),2);//ResponseTime
					}
				}
				for (int y = 0; y < sums.length; y++) {//variance and standard deviation
					result.addStatistic(st2[1], se[y], sums[y][0]/(n-1));
					result.addStatistic(st2[6], se[y], sums[y][1]/(n-1));
					result.addStatistic(st2[11], se[y], sums[y][2]/(n-1));
					result.addStatistic(st2[2], se[y], Math.sqrt(sums[y][0]/(n-1)));
					result.addStatistic(st2[7], se[y], Math.sqrt(sums[y][1]/(n-1)));
					result.addStatistic(st2[12], se[y], Math.sqrt(sums[y][2]/(n-1)));
				}
				for(SystemElement element:se){//confidence intervals
					result.addStatistic(st2[3], element, result.getValue(st2[0],element)-(confidenceDegree*result.getValue(st2[2], element)/sqrtN));
					result.addStatistic(st2[4], element, result.getValue(st2[0],element)+(confidenceDegree*result.getValue(st2[2], element)/sqrtN));
					result.addStatistic(st2[8], element, result.getValue(st2[5],element)-(confidenceDegree*result.getValue(st2[7], element)/sqrtN));
					result.addStatistic(st2[9], element, result.getValue(st2[5],element)+(confidenceDegree*result.getValue(st2[7], element)/sqrtN));
					result.addStatistic(st2[13], element, result.getValue(st2[10],element)-(confidenceDegree*result.getValue(st2[12], element)/sqrtN));
					result.addStatistic(st2[14], element, result.getValue(st2[10],element)+(confidenceDegree*result.getValue(st2[12], element)/sqrtN));
				}
				System.out.println("Fine calcolo nuove statistiche");
				de[i].export(result);
			}
		}
		de[0].endExporting();
		de[1].endExporting();
		System.out.println("Fine simulazione");
	}
}
